#include "stdafx.h"
#include "ASTNode.h"


namespace AST {
Node::Node() :id(0), nodeVertex(), tree(0), isLeaf(false), nodeName("")
{

}

Node::Node(CXCursor cxcursor, unsigned long nodeId, std::string nodeName, ASTree*  ownerTree) : cursor(cxcursor), 
																								id(nodeId), 
																								tree(ownerTree), 
																								nodeName(nodeName)
{
	isLeaf = true;
	ngrams=0;
}

Node::~Node(void)
{
	if (ngrams!=0)
		delete ngrams;
}

Node* Node::createNode(CXCursor cxcursor, unsigned long nodeId, std::string nodeName, ASTree*  ownerTree){

	switch (cxcursor.kind){
		case CXCursor_ClassDecl:
			return new ClassDeclNode (cxcursor, nodeId, nodeName, ownerTree);
		case CXCursor_TranslationUnit:
			return new TranslationUnitNode (cxcursor, nodeId, nodeName, ownerTree);
		default:
			return  new Node(cxcursor, nodeId, nodeName, ownerTree);

	}
/*	if (cxcursor.kind == CXCursor_ClassDecl){
	}
	else {
		return  new Node(cxcursor, nodeId, ownerTree);
	}
	*/
}

void Node::setVertex (const vertexDesc vertex){
	nodeVertex	= vertex;
}

vertexDesc& Node::getVertex (){
	return this->nodeVertex;
}

void Node::leaf (bool isLeaf){
	this->isLeaf = isLeaf;
}

bool Node::leaf () {
	return isLeaf;
}

CXCursorKind Node::getKind(){
	return cursor.kind;
}

float Node::match (Node& node){
	float similarity = (float) (cursor.kind == node.cursor.kind)?0.75f:0.0f;
	similarity += (clang_getCursorType(cursor).kind == clang_getCursorType(node.cursor).kind)?0.25f:0.0f;
	similarity *= ngramSimilarity(getNgrams(Node::ngramWindowSize), node.getNgrams(Node::ngramWindowSize));
	return similarity;
}

float Node::ngramSimilarity(const ngramSet* ngramsA, const ngramSet* ngramsB){
	if (ngramsA->size() == ngramsB->size() && ngramsB->size() == 0)
		return 1.0;
	if (ngramsA->size() == 0 || ngramsB->size() == 0)
		return 0.0;

	unsigned int matches =0;
	for (ngramSet::iterator iter = ngramsA->begin(); iter!= ngramsA->end(); iter++)
		if (ngramsB->find(*iter) != ngramsB->end())
			matches++;

	//dice coefficient
	float sim = ((float)2*matches)/(ngramsA->size()+ngramsB->size());
	return sim;
}

ngramSet const * Node::getNgrams(unsigned int windowSize){
	if (ngrams==0){
		ngrams = new ngramSet();
		char const *  text = clang_getCString(clang_getCursorDisplayName(cursor));
		unsigned int value=0;
		unsigned int length = strlen(text);
		if (length==0 && leaf()){
			text = nodeSource().c_str();
			length = nodeSource().size();
		}
		if (length<=windowSize){
			for(unsigned int j=0; j<length; j++)
					value += ((unsigned int) text[j])<<j*windowSize;
			ngrams->insert(value);
		}
		else{
			for (unsigned i=0; i<=length-windowSize; i++){
				for(unsigned int j=0; j<windowSize; j++)
					value +=  ((unsigned int) text[j+i])<<(j*windowSize);
				ngrams->insert(value);
				value=0;
			}
		}
	}
	return ngrams;
}


std::string& Node::nodeSource(){
	return sourceSnippet;
}

void Node::nodeSource(std::string source){
	sourceSnippet = source;
}

GenericNode::GenericNode() : Node()
{
	
}

GenericNode::GenericNode(CXCursor cxcursor, unsigned long nodeId, std::string nodeName, ASTree*  ownerTree) : Node(cxcursor, nodeId, nodeName, ownerTree)
{

}

GenericNode::~GenericNode(void)
{
}

ClassDeclNode::ClassDeclNode() :GenericNode()
{

}

ClassDeclNode::ClassDeclNode(CXCursor cxcursor, unsigned long nodeId, std::string nodeName, ASTree*  ownerTree) : GenericNode(cxcursor, nodeId, nodeName, ownerTree)
{

}

ClassDeclNode::~ClassDeclNode(void)
{
}



TranslationUnitNode::TranslationUnitNode() :GenericNode()
{

}

TranslationUnitNode::TranslationUnitNode(CXCursor cxcursor, unsigned long nodeId, std::string nodeName, ASTree*  ownerTree) : GenericNode(cxcursor, nodeId, nodeName, ownerTree)
{

}

TranslationUnitNode::~TranslationUnitNode(void)
{
}
} //namespace AST